PSI2IR KT-49526 function reference type approximation hack

This commit is contained in:
Dmitry Petrov
2021-12-17 16:18:11 +03:00
committed by Space
parent 9c0ea11c1b
commit 976998b56c
21 changed files with 360 additions and 1 deletions
@@ -2991,6 +2991,30 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/callableReference/kt47988.kt");
}
@Test
@TestMetadata("kt49526.kt")
public void testKt49526() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526.kt");
}
@Test
@TestMetadata("kt49526_sam.kt")
public void testKt49526_sam() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526_sam.kt");
}
@Test
@TestMetadata("kt49526a.kt")
public void testKt49526a() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526a.kt");
}
@Test
@TestMetadata("kt49526b.kt")
public void testKt49526b() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526b.kt");
}
@Test
@TestMetadata("kt50172.kt")
public void testKt50172() throws Exception {
@@ -3018,6 +3018,12 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest {
runTest("compiler/testData/ir/irText/types/kt36143.kt");
}
@Test
@TestMetadata("kt49526.kt")
public void testKt49526() throws Exception {
runTest("compiler/testData/ir/irText/types/kt49526.kt");
}
@Test
@TestMetadata("localVariableOfIntersectionType.kt")
public void testLocalVariableOfIntersectionType() throws Exception {
@@ -74,7 +74,10 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
fun generateCallableReference(ktCallableReference: KtCallableReferenceExpression): IrExpression {
val resolvedCall = getResolvedCall(ktCallableReference.callableReference)!!
val resolvedDescriptor = resolvedCall.resultingDescriptor
val callableReferenceType = getTypeInferredByFrontendOrFail(ktCallableReference)
val callableReferenceType =
context.typeTranslator.approximateFunctionReferenceType(
getTypeInferredByFrontendOrFail(ktCallableReference)
)
val callBuilder = unwrapCallableDescriptorAndTypeArguments(resolvedCall)
return when {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.builtins.isKFunctionType
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
@@ -203,6 +204,38 @@ abstract class TypeTranslator(
return properlyApproximatedType
}
fun approximateFunctionReferenceType(kotlinType: KotlinType): KotlinType {
// This is a hack to support intersection types in function references on JVM.
// Function reference type KFunctionN<T1, ..., TN, R> might contain intersection types in its top-level arguments.
// Intersection types in expressions and local variable declarations usually don't bother us.
// However, in case of function references type mapping affects behavior:
// resulting function reference class will have a bridge method, which will downcast its arguments to the expected types.
// This would cause ClassCastException in case of usual type approximation,
// because '{ X1 & ... & Xm }' would be approximated to 'Nothing'.
// JVM_OLD just relies on type mapping for generic argument types in such case.
if (!kotlinType.isKFunctionType)
return kotlinType
if (kotlinType !is SimpleType)
return kotlinType
if (kotlinType.arguments.none { it.type.constructor is IntersectionTypeConstructor })
return kotlinType
val functionParameterTypes = kotlinType.arguments.subList(0, kotlinType.arguments.size - 1)
val functionReturnType = kotlinType.arguments.last()
return kotlinType.replace(
newArguments = functionParameterTypes.map { approximateFunctionReferenceParameterType(it) } + functionReturnType
)
}
private fun approximateFunctionReferenceParameterType(typeProjection: TypeProjection): TypeProjection {
if (typeProjection.isStarProjection) return typeProjection
val typeConstructor = typeProjection.type.constructor as? IntersectionTypeConstructor
?: return typeProjection
// 'mapType' takes common supertype for intersection type supertypes, regardless of variance.
val newType = typeConstructor.getAlternativeType()
?: commonSupertype(typeConstructor.supertypes)
return TypeProjectionImpl(typeProjection.projectionKind, newType)
}
private val isWithNewInference = languageVersionSettings.supportsFeature(LanguageFeature.NewInference)
private fun approximateByKotlinRules(ktType: KotlinType): KotlinType =
@@ -0,0 +1,12 @@
// IGNORE_BACKEND_FIR: JVM_IR
// FIR_STATUS: callable reference type approximation hack not implemented
// WITH_STDLIB
// CHECK_BYTECODE_LISTING
inline fun <T> useRef(value: T, f: (T) -> Boolean) = f(value)
fun box(): String {
val chars = listOf('a') + "-"
return if (useRef('a', chars::contains)) "OK" else "Failed"
}
@@ -0,0 +1,6 @@
@kotlin.Metadata
public final class Kt49526Kt {
// source: 'kt49526.kt'
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static method useRef(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function1): boolean
}
@@ -0,0 +1,35 @@
// IGNORE_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// IGNORE_BACKEND_FIR: JVM_IR
// FIR_STATUS: LambdaConversionException: Type mismatch for lambda argument 1: class java.lang.Object is not convertible to interface I1
// JVM_IR it this case has an approximated type 'KFun<out Any>', which has a projected top-level argument.
fun <T> intersect(x: T, y: T): T = x
interface I1
interface I2
class C1 : I1, I2 {
override fun toString(): String = "OK"
}
class C2 : I1, I2
fun <T> T.k() = K<T>(this)
fun interface KFun<T> {
fun invoke(x: T)
}
class K<T>(private val x: T) {
fun with(kf: KFun<T>) {
kf.invoke(x)
}
}
fun box(): String {
var result = "Failed"
intersect(C1(), C2()).k().with { result = it.toString() }
return result
}
@@ -0,0 +1,20 @@
// IGNORE_BACKEND_FIR: JVM_IR
// FIR_STATUS: callable reference type approximation hack not implemented
fun <T> id(x: T): T = x
fun <T> intersect(x: T, y: T): T = x
interface I1
interface I2
class C1 : I1, I2 {
override fun toString() = "OK"
}
class C2 : I1, I2
fun box() =
intersect(C1(), C2())
.let(::id)
.toString()
@@ -0,0 +1,12 @@
// IGNORE_BACKEND_FIR: JVM_IR
// FIR_STATUS: callable reference type approximation hack not implemented
// WITH_STDLIB
inline fun <T> useRef(value: T, f: (T) -> Boolean) = f(value)
fun box(): String {
val chars = listOf('a') + "-"
val ref = chars::contains
return if (ref('a')) "OK" else "Failed"
}
+15
View File
@@ -0,0 +1,15 @@
FILE fqName:<root> fileName:/kt49526.kt
FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Boolean
BLOCK_BODY
VAR name:ref type:kotlin.reflect.KFunction1<kotlin.Nothing, kotlin.Boolean> [val]
FUNCTION_REFERENCE 'public abstract fun contains (element: E of kotlin.collections.List): kotlin.Boolean [operator] declared in kotlin.collections.List' type=kotlin.reflect.KFunction1<kotlin.Nothing, kotlin.Boolean> origin=null reflectionTarget=<same>
$this: CALL 'public final fun plus <T> (element: T of kotlin.collections.CollectionsKt.plus): kotlin.collections.List<T of kotlin.collections.CollectionsKt.plus> [operator] declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List<kotlin.Any> origin=PLUS
<T>: kotlin.Comparable<kotlin.Nothing>
$receiver: CALL 'public final fun listOf <T> (element: T of kotlin.collections.CollectionsKt.listOf): kotlin.collections.List<T of kotlin.collections.CollectionsKt.listOf> declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List<kotlin.Char> origin=null
<T>: kotlin.Char
element: CONST Char type=kotlin.Char value='a'
element: CONST String type=kotlin.String value="-"
RETURN type=kotlin.Nothing from='public final fun test (): kotlin.Boolean declared in <root>'
CALL 'public abstract fun invoke (p1: P1 of kotlin.reflect.KFunction1): R of kotlin.reflect.KFunction1 [operator] declared in kotlin.reflect.KFunction1' type=kotlin.Boolean origin=INVOKE
$this: GET_VAR 'val ref: kotlin.reflect.KFunction1<kotlin.Nothing, kotlin.Boolean> [val] declared in <root>.test' type=kotlin.reflect.KFunction1<kotlin.Nothing, kotlin.Boolean> origin=VARIABLE_AS_FUNCTION
p1: CONST Char type=kotlin.Char value='a'
+15
View File
@@ -0,0 +1,15 @@
FILE fqName:<root> fileName:/kt49526.kt
FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Boolean
BLOCK_BODY
VAR name:ref type:kotlin.reflect.KFunction1<kotlin.Nothing, kotlin.Boolean> [val]
FUNCTION_REFERENCE 'public abstract fun contains (element: E of kotlin.collections.List): kotlin.Boolean [operator] declared in kotlin.collections.List' type=kotlin.reflect.KFunction1<kotlin.Any, kotlin.Boolean> origin=null reflectionTarget=<same>
$this: CALL 'public final fun plus <T> (element: T of kotlin.collections.CollectionsKt.plus): kotlin.collections.List<T of kotlin.collections.CollectionsKt.plus> [operator] declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List<kotlin.Any> origin=PLUS
<T>: kotlin.Any
$receiver: CALL 'public final fun listOf <T> (element: T of kotlin.collections.CollectionsKt.listOf): kotlin.collections.List<T of kotlin.collections.CollectionsKt.listOf> declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List<kotlin.Char> origin=null
<T>: kotlin.Char
element: CONST Char type=kotlin.Char value='a'
element: CONST String type=kotlin.String value="-"
RETURN type=kotlin.Nothing from='public final fun test (): kotlin.Boolean declared in <root>'
CALL 'public abstract fun invoke (p1: P1 of kotlin.reflect.KFunction1): R of kotlin.reflect.KFunction1 [fake_override,operator] declared in kotlin.reflect.KFunction1' type=kotlin.Boolean origin=INVOKE
$this: GET_VAR 'val ref: kotlin.reflect.KFunction1<kotlin.Nothing, kotlin.Boolean> [val] declared in <root>.test' type=kotlin.reflect.KFunction1<kotlin.Nothing, kotlin.Boolean> origin=VARIABLE_AS_FUNCTION
p1: CONST Char type=kotlin.Char value='a'
+7
View File
@@ -0,0 +1,7 @@
// WITH_STDLIB
// SKIP_KT_DUMP
fun test(): Boolean {
val ref = (listOf('a') + "-")::contains
return ref('a')
}
@@ -2913,6 +2913,30 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/callableReference/kt47988.kt");
}
@Test
@TestMetadata("kt49526.kt")
public void testKt49526() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526.kt");
}
@Test
@TestMetadata("kt49526_sam.kt")
public void testKt49526_sam() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526_sam.kt");
}
@Test
@TestMetadata("kt49526a.kt")
public void testKt49526a() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526a.kt");
}
@Test
@TestMetadata("kt49526b.kt")
public void testKt49526b() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526b.kt");
}
@Test
@TestMetadata("kt50172.kt")
public void testKt50172() throws Exception {
@@ -2991,6 +2991,30 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/callableReference/kt47988.kt");
}
@Test
@TestMetadata("kt49526.kt")
public void testKt49526() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526.kt");
}
@Test
@TestMetadata("kt49526_sam.kt")
public void testKt49526_sam() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526_sam.kt");
}
@Test
@TestMetadata("kt49526a.kt")
public void testKt49526a() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526a.kt");
}
@Test
@TestMetadata("kt49526b.kt")
public void testKt49526b() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526b.kt");
}
@Test
@TestMetadata("kt50172.kt")
public void testKt50172() throws Exception {
@@ -3018,6 +3018,12 @@ public class IrTextTestGenerated extends AbstractIrTextTest {
runTest("compiler/testData/ir/irText/types/kt36143.kt");
}
@Test
@TestMetadata("kt49526.kt")
public void testKt49526() throws Exception {
runTest("compiler/testData/ir/irText/types/kt49526.kt");
}
@Test
@TestMetadata("localVariableOfIntersectionType.kt")
public void testLocalVariableOfIntersectionType() throws Exception {
@@ -2425,6 +2425,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/callableReference/kt21092b.kt");
}
@TestMetadata("kt49526_sam.kt")
public void ignoreKt49526_sam() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526_sam.kt");
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
@@ -2558,6 +2563,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/callableReference/kt47988.kt");
}
@TestMetadata("kt49526.kt")
public void testKt49526() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526.kt");
}
@TestMetadata("kt49526a.kt")
public void testKt49526a() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526a.kt");
}
@TestMetadata("kt49526b.kt")
public void testKt49526b() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526b.kt");
}
@TestMetadata("kt50172.kt")
public void testKt50172() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt50172.kt");
@@ -2192,6 +2192,11 @@ public class KlibTextTestCaseGenerated extends AbstractKlibTextTestCase {
runTest("compiler/testData/ir/irText/types/kt36143.kt");
}
@TestMetadata("kt49526.kt")
public void testKt49526() throws Exception {
runTest("compiler/testData/ir/irText/types/kt49526.kt");
}
@TestMetadata("localVariableOfIntersectionType.kt")
public void testLocalVariableOfIntersectionType() throws Exception {
runTest("compiler/testData/ir/irText/types/localVariableOfIntersectionType.kt");
@@ -1911,6 +1911,30 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/callableReference/kt47988.kt");
}
@Test
@TestMetadata("kt49526.kt")
public void testKt49526() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526.kt");
}
@Test
@TestMetadata("kt49526_sam.kt")
public void testKt49526_sam() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526_sam.kt");
}
@Test
@TestMetadata("kt49526a.kt")
public void testKt49526a() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526a.kt");
}
@Test
@TestMetadata("kt49526b.kt")
public void testKt49526b() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526b.kt");
}
@Test
@TestMetadata("kt50172.kt")
public void testKt50172() throws Exception {
@@ -1953,6 +1953,30 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/callableReference/kt47988.kt");
}
@Test
@TestMetadata("kt49526.kt")
public void testKt49526() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526.kt");
}
@Test
@TestMetadata("kt49526_sam.kt")
public void testKt49526_sam() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526_sam.kt");
}
@Test
@TestMetadata("kt49526a.kt")
public void testKt49526a() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526a.kt");
}
@Test
@TestMetadata("kt49526b.kt")
public void testKt49526b() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526b.kt");
}
@Test
@TestMetadata("kt50172.kt")
public void testKt50172() throws Exception {
@@ -1748,6 +1748,26 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/callableReference/kt47988.kt");
}
@TestMetadata("kt49526.kt")
public void testKt49526() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526.kt");
}
@TestMetadata("kt49526_sam.kt")
public void testKt49526_sam() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526_sam.kt");
}
@TestMetadata("kt49526a.kt")
public void testKt49526a() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526a.kt");
}
@TestMetadata("kt49526b.kt")
public void testKt49526b() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526b.kt");
}
@TestMetadata("kt50172.kt")
public void testKt50172() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt50172.kt");
@@ -1978,6 +1978,30 @@ public class NativeExtBlackBoxTestGenerated extends AbstractNativeBlackBoxTest {
runTest("compiler/testData/codegen/box/callableReference/kt47988.kt");
}
@Test
@TestMetadata("kt49526.kt")
public void testKt49526() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526.kt");
}
@Test
@TestMetadata("kt49526_sam.kt")
public void testKt49526_sam() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526_sam.kt");
}
@Test
@TestMetadata("kt49526a.kt")
public void testKt49526a() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526a.kt");
}
@Test
@TestMetadata("kt49526b.kt")
public void testKt49526b() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/kt49526b.kt");
}
@Test
@TestMetadata("kt50172.kt")
public void testKt50172() throws Exception {