K2: Do not use KFunctionN as representation type for adapted references
Beside some corner cases, it's already prohibited in K1 because adaptation have a bit strange nature (they don't represent any existing real function exactly) ^KT-55137 Fixed
This commit is contained in:
committed by
Space Team
parent
dcdc48a233
commit
a38040680c
+6
@@ -3111,6 +3111,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/callableReference/adapted"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noKFunctionForAdaptation.kt")
|
||||
public void testNoKFunctionForAdaptation() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/callableReference/adapted/noKFunctionForAdaptation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleAdaptationOutsideOfCall.kt")
|
||||
public void testSimpleAdaptationOutsideOfCall() throws Exception {
|
||||
|
||||
+6
@@ -3117,6 +3117,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/callableReference/adapted"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noKFunctionForAdaptation.kt")
|
||||
public void testNoKFunctionForAdaptation() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/callableReference/adapted/noKFunctionForAdaptation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleAdaptationOutsideOfCall.kt")
|
||||
public void testSimpleAdaptationOutsideOfCall() throws Exception {
|
||||
|
||||
+6
@@ -3111,6 +3111,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/callableReference/adapted"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noKFunctionForAdaptation.kt")
|
||||
public void testNoKFunctionForAdaptation() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/callableReference/adapted/noKFunctionForAdaptation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleAdaptationOutsideOfCall.kt")
|
||||
public void testSimpleAdaptationOutsideOfCall() throws Exception {
|
||||
|
||||
+1
-5
@@ -98,8 +98,7 @@ internal class AdapterGenerator(
|
||||
* At the use site, instead of referenced, we can put the suspend lambda as an adapter.
|
||||
*/
|
||||
private fun needSuspendConversion(type: IrSimpleType, function: IrFunction): Boolean =
|
||||
// TODO: should refer to LanguageVersionSettings.SuspendConversion
|
||||
type.isKSuspendFunction() && !function.isSuspend
|
||||
type.isSuspendFunction() && !function.isSuspend
|
||||
|
||||
/**
|
||||
* For example,
|
||||
@@ -133,9 +132,6 @@ internal class AdapterGenerator(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ConeKotlinType.kFunctionTypeToFunctionType(): IrSimpleType =
|
||||
reflectFunctionTypeToNonReflectFunctionType(session).toIrType() as IrSimpleType
|
||||
|
||||
internal fun generateAdaptedCallableReference(
|
||||
callableReferenceAccess: FirCallableReferenceAccess,
|
||||
explicitReceiverExpression: IrExpression?,
|
||||
|
||||
+2
-1
@@ -156,7 +156,8 @@ class CallAndReferenceGenerator(
|
||||
if (adapterGenerator.needToGenerateAdaptedCallableReference(callableReferenceAccess, type, function)) {
|
||||
// Receivers are being applied inside
|
||||
with(adapterGenerator) {
|
||||
val adaptedType = callableReferenceAccess.typeRef.coneType.kFunctionTypeToFunctionType()
|
||||
// TODO: Figure out why `adaptedType` is different from the `type`?
|
||||
val adaptedType = callableReferenceAccess.typeRef.coneType.toIrType() as IrSimpleType
|
||||
generateAdaptedCallableReference(callableReferenceAccess, explicitReceiverExpression, symbol, adaptedType)
|
||||
}
|
||||
} else {
|
||||
|
||||
+6
@@ -18319,6 +18319,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/fir/assertEqualsFakeOverride.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("callableReferenceConversionTopLevel.kt")
|
||||
public void testCallableReferenceConversionTopLevel() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/fir/callableReferenceConversionTopLevel.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("callableReferenceToJavaField.kt")
|
||||
public void testCallableReferenceToJavaField() throws Exception {
|
||||
|
||||
+11
-1
@@ -136,7 +136,7 @@ private fun buildReflectionType(
|
||||
?: FunctionTypeKind.Function
|
||||
|
||||
return createFunctionType(
|
||||
baseFunctionTypeKind.reflectKind(),
|
||||
if (callableReferenceAdaptation == null) baseFunctionTypeKind.reflectKind() else baseFunctionTypeKind.nonReflectKind(),
|
||||
parameters,
|
||||
receiverType = receiverType.takeIf { fir.receiverParameter != null },
|
||||
rawReturnType = returnType,
|
||||
@@ -239,9 +239,11 @@ private fun BodyResolveComponents.getCallableReferenceAdaptation(
|
||||
mappedArguments[valueParameter] = ResolvedCallArgument.VarargArgument(varargElements)
|
||||
}
|
||||
|
||||
var isThereVararg = mappedVarargElements.isNotEmpty()
|
||||
for (valueParameter in function.valueParameters) {
|
||||
if (valueParameter.isVararg && valueParameter !in mappedArguments) {
|
||||
mappedArguments[valueParameter] = ResolvedCallArgument.VarargArgument(emptyList())
|
||||
isThereVararg = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +266,14 @@ private fun BodyResolveComponents.getCallableReferenceAdaptation(
|
||||
CallableReferenceConversionStrategy.NoConversion
|
||||
}
|
||||
|
||||
if (defaults == 0 && !isThereVararg &&
|
||||
coercionStrategy == CoercionStrategy.NO_COERCION && conversionStrategy == CallableReferenceConversionStrategy.NoConversion
|
||||
) {
|
||||
// Do not create adaptation for trivial (id) conversion as it makes resulting type FunctionN instead of KFunctionN
|
||||
// It happens because adapted references do not support reflection (see KT-40406)
|
||||
return null
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return CallableReferenceAdaptation(
|
||||
mappedArgumentTypes as Array<ConeKotlinType>,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_K1: JVM_IR
|
||||
|
||||
fun foo(x: String = "OK"): String = x
|
||||
|
||||
fun box(): String {
|
||||
val f: () -> String = ::foo
|
||||
return f()
|
||||
}
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
// SKIP_TXT
|
||||
fun foo(x: String = "O"): String = x
|
||||
fun bar(x: String = "K"): String = x
|
||||
|
||||
fun dump(dumpStrategy: String) {
|
||||
val k0: kotlin.reflect.KFunction0<String> = <!INAPPLICABLE_CANDIDATE!>returnAdapter<!>(::<!UNRESOLVED_REFERENCE!>foo<!>) // Error: ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE
|
||||
val k1: kotlin.reflect.KFunction0<String> = ::<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
// Should be error here, too
|
||||
val k2: kotlin.reflect.KFunction0<String> = if (dumpStrategy == "KotlinLike") ::<!UNRESOLVED_REFERENCE!>foo<!> else ::<!UNRESOLVED_REFERENCE!>bar<!>
|
||||
|
||||
val f0: Function0<String> = <!INAPPLICABLE_CANDIDATE!>returnAdapter<!>(::<!UNRESOLVED_REFERENCE!>foo<!>)
|
||||
val f1: Function0<String> = ::foo
|
||||
val f2: Function0<String> = if (dumpStrategy == "KotlinLike") ::<!UNRESOLVED_REFERENCE!>foo<!> else ::<!UNRESOLVED_REFERENCE!>bar<!>
|
||||
}
|
||||
|
||||
fun returnAdapter(a: kotlin.reflect.KFunction0<String>) = a
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// SKIP_TXT
|
||||
fun foo(x: String = "O"): String = x
|
||||
fun bar(x: String = "K"): String = x
|
||||
|
||||
fun dump(dumpStrategy: String) {
|
||||
val k0: kotlin.reflect.KFunction0<String> = returnAdapter(<!ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE!>::foo<!>) // Error: ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE
|
||||
val k1: kotlin.reflect.KFunction0<String> = <!TYPE_MISMATCH!>::<!TYPE_MISMATCH!>foo<!><!>
|
||||
// Should be error here, too
|
||||
val k2: kotlin.reflect.KFunction0<String> = if (dumpStrategy == "KotlinLike") ::foo else ::bar
|
||||
|
||||
val f0: Function0<String> = returnAdapter(<!ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE!>::foo<!>)
|
||||
val f1: Function0<String> = <!TYPE_MISMATCH!>::<!TYPE_MISMATCH!>foo<!><!>
|
||||
val f2: Function0<String> = if (dumpStrategy == "KotlinLike") ::foo else ::bar
|
||||
}
|
||||
|
||||
fun returnAdapter(a: kotlin.reflect.KFunction0<String>) = a
|
||||
+1
-1
@@ -22,6 +22,6 @@ object Local {
|
||||
fun baz(x: Int, y: Int = 0): Int = 0
|
||||
|
||||
fun test() {
|
||||
bar(::baz)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar<!>(::<!UNRESOLVED_REFERENCE!>baz<!>)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,6 +22,6 @@ object Local {
|
||||
fun baz(x: Int, y: Int = 0): Int = 0
|
||||
|
||||
fun test() {
|
||||
bar(::baz)
|
||||
<!INAPPLICABLE_CANDIDATE!>bar<!>(::<!UNRESOLVED_REFERENCE!>baz<!>)
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+6
-6
@@ -107,7 +107,7 @@ FILE fqName:<root> fileName:/caoWithAdaptationForSam.kt
|
||||
BLOCK type=kotlin.Unit origin=null
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:<root>.A [val]
|
||||
GET_OBJECT 'CLASS OBJECT name:A modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.A
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit> [val]
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Function1<kotlin.Int, kotlin.Unit> [val]
|
||||
FUN_EXPR type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE
|
||||
FUN ADAPTER_FOR_CALLABLE_REFERENCE name:withVararg visibility:local modality:FINAL <> (p0:kotlin.Int) returnType:kotlin.Unit
|
||||
VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int
|
||||
@@ -118,19 +118,19 @@ FILE fqName:<root> fileName:/caoWithAdaptationForSam.kt
|
||||
CALL 'public final fun set (i: <root>.IFoo, newValue: kotlin.Int): kotlin.Unit [operator] declared in <root>' type=kotlin.Unit origin=null
|
||||
$receiver: GET_VAR 'val tmp_0: <root>.A [val] declared in <root>.test1' type=<root>.A origin=null
|
||||
i: TYPE_OP type=<root>.IFoo origin=SAM_CONVERSION typeOperand=<root>.IFoo
|
||||
GET_VAR 'val tmp_1: kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit> [val] declared in <root>.test1' type=kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit> origin=null
|
||||
GET_VAR 'val tmp_1: kotlin.Function1<kotlin.Int, kotlin.Unit> [val] declared in <root>.test1' type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=null
|
||||
newValue: CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
|
||||
$this: CALL 'public final fun get (i: <root>.IFoo): kotlin.Int [operator] declared in <root>' type=kotlin.Int origin=null
|
||||
$receiver: GET_VAR 'val tmp_0: <root>.A [val] declared in <root>.test1' type=<root>.A origin=null
|
||||
i: TYPE_OP type=<root>.IFoo origin=SAM_CONVERSION typeOperand=<root>.IFoo
|
||||
GET_VAR 'val tmp_1: kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit> [val] declared in <root>.test1' type=kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit> origin=null
|
||||
GET_VAR 'val tmp_1: kotlin.Function1<kotlin.Int, kotlin.Unit> [val] declared in <root>.test1' type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=null
|
||||
other: CONST Int type=kotlin.Int value=1
|
||||
FUN name:test2 visibility:public modality:FINAL <> () returnType:kotlin.Unit
|
||||
BLOCK_BODY
|
||||
BLOCK type=kotlin.Unit origin=null
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:<root>.B [val]
|
||||
GET_OBJECT 'CLASS OBJECT name:B modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.B
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit> [val]
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.Function1<kotlin.Int, kotlin.Unit> [val]
|
||||
FUN_EXPR type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE
|
||||
FUN ADAPTER_FOR_CALLABLE_REFERENCE name:withVararg visibility:local modality:FINAL <> (p0:kotlin.Int) returnType:kotlin.Unit
|
||||
VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int
|
||||
@@ -141,12 +141,12 @@ FILE fqName:<root> fileName:/caoWithAdaptationForSam.kt
|
||||
CALL 'public final fun set (i: <root>.IFoo2, newValue: kotlin.Int): kotlin.Unit [operator] declared in <root>' type=kotlin.Unit origin=null
|
||||
$receiver: GET_VAR 'val tmp_2: <root>.B [val] declared in <root>.test2' type=<root>.B origin=null
|
||||
i: TYPE_OP type=<root>.IFoo2 origin=SAM_CONVERSION typeOperand=<root>.IFoo2
|
||||
GET_VAR 'val tmp_3: kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit> [val] declared in <root>.test2' type=kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit> origin=null
|
||||
GET_VAR 'val tmp_3: kotlin.Function1<kotlin.Int, kotlin.Unit> [val] declared in <root>.test2' type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=null
|
||||
newValue: CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null
|
||||
$this: CALL 'public final fun get (i: <root>.IFoo): kotlin.Int [operator] declared in <root>' type=kotlin.Int origin=null
|
||||
$receiver: GET_VAR 'val tmp_2: <root>.B [val] declared in <root>.test2' type=<root>.B origin=null
|
||||
i: TYPE_OP type=<root>.IFoo origin=SAM_CONVERSION typeOperand=<root>.IFoo
|
||||
GET_VAR 'val tmp_3: kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit> [val] declared in <root>.test2' type=kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit> origin=null
|
||||
GET_VAR 'val tmp_3: kotlin.Function1<kotlin.Int, kotlin.Unit> [val] declared in <root>.test2' type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=null
|
||||
other: CONST Int type=kotlin.Int value=1
|
||||
FUN name:test3 visibility:public modality:FINAL <> (fn:kotlin.Function1<kotlin.Int, kotlin.Unit>) returnType:kotlin.Unit
|
||||
VALUE_PARAMETER name:fn index:0 type:kotlin.Function1<kotlin.Int, kotlin.Unit>
|
||||
|
||||
Vendored
+2
-2
@@ -46,7 +46,7 @@ fun withVararg(vararg xs: Int): Int {
|
||||
fun test1() {
|
||||
{ // BLOCK
|
||||
val <array>: A = A
|
||||
val <index_0>: KFunction1<Int, Unit> = local fun withVararg(p0: Int) {
|
||||
val <index_0>: Function1<Int, Unit> = local fun withVararg(p0: Int) {
|
||||
withVararg(xs = [p0])
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ fun test1() {
|
||||
fun test2() {
|
||||
{ // BLOCK
|
||||
val <array>: B = B
|
||||
val <index_0>: KFunction1<Int, Unit> = local fun withVararg(p0: Int) {
|
||||
val <index_0>: Function1<Int, Unit> = local fun withVararg(p0: Int) {
|
||||
withVararg(xs = [p0])
|
||||
}
|
||||
|
||||
|
||||
Generated
+6
@@ -3117,6 +3117,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/callableReference/adapted"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noKFunctionForAdaptation.kt")
|
||||
public void testNoKFunctionForAdaptation() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/callableReference/adapted/noKFunctionForAdaptation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleAdaptationOutsideOfCall.kt")
|
||||
public void testSimpleAdaptationOutsideOfCall() throws Exception {
|
||||
|
||||
+6
@@ -18319,6 +18319,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/fir/assertEqualsFakeOverride.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("callableReferenceConversionTopLevel.kt")
|
||||
public void testCallableReferenceConversionTopLevel() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/fir/callableReferenceConversionTopLevel.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("callableReferenceToJavaField.kt")
|
||||
public void testCallableReferenceToJavaField() throws Exception {
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ class Case2() {
|
||||
}
|
||||
|
||||
fun case() {
|
||||
foo(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction1<kotlin.Int, kotlin.String>")!>::invoke<!>, <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction1<kotlin.Int, kotlin.String>")!>::invoke<!>)
|
||||
foo(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Int, kotlin.String>")!>::invoke<!>, <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Int, kotlin.String>")!>::invoke<!>)
|
||||
foo(::invoke, ::invoke)
|
||||
<!DEBUG_INFO_CALL("fqName: Case2.foo; typeCall: function")!>foo(::invoke, ::invoke)<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>foo(::invoke, ::invoke)<!>
|
||||
|
||||
Reference in New Issue
Block a user