JVM_IR: use indy SAM conversions in jvmTarget 1.8+, fix bridges

KT-44278 KT-26060 KT-42621
This commit is contained in:
Dmitry Petrov
2021-02-05 15:23:04 +03:00
parent 6c6d43c29a
commit 3ebeca5852
50 changed files with 1293 additions and 287 deletions
@@ -1,5 +1,6 @@
// TARGET_BACKEND: JVM
// SAM_CONVERSIONS: CLASS
// ^ test checks reflection for synthetic classes
// WITH_RUNTIME
// FILE: Test.java
@@ -9,9 +10,10 @@ class Test {
}
}
// FILE: test.kt
// FILE: samLambda.kt
import java.lang.reflect.Method
import kotlin.test.assertEquals
@Target(AnnotationTarget.FUNCTION)
@@ -8,6 +8,6 @@ fun lambdaIsSerializable(fn: () -> Unit) = fn is java.io.Serializable
fun box(): String {
if (lambdaIsSerializable {})
return "Failed: indy lambdas are not serializable"
return "Failed: indy lambdas should not be serializable"
return "OK"
}
@@ -0,0 +1,14 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
fun interface KRunnable {
fun run()
}
var test = "Failed"
fun box(): String {
KRunnable { test = "OK" }.run()
return test
}
@@ -0,0 +1,13 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
fun interface IFooAny {
fun foo(x: Any): Any
}
fun interface IFooStr : IFooAny {
override fun foo(x: Any): String
}
fun box() = IFooStr { x: Any -> x.toString() }.foo("OK")
@@ -0,0 +1,20 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
fun interface IFooNStr {
fun foo(x: Any): String?
}
fun interface IFooNN : IFooNStr {
override fun foo(x: Any): Nothing?
}
fun box(): String {
var r = "Failed"
IFooNN {
r = it.toString()
null
}.foo("OK")
return r
}
@@ -0,0 +1,15 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// IGNORE_DEXING
fun interface GenericToAny<T> {
fun invoke(x: T): Any
}
fun interface GenericCharToAny : GenericToAny<Char>
fun withK(fn: GenericCharToAny) = fn.invoke('K').toString()
fun box(): String =
withK { "O" + it }
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
fun interface GenericToAny<T> {
fun invoke(x: T): Any
}
fun interface CharToAny {
fun invoke(x: Char): Any
}
fun interface GenericCharToAny : GenericToAny<Char>, CharToAny
fun withK(fn: GenericCharToAny) = fn.invoke('K').toString()
fun box(): String =
withK { "O" + it }
@@ -0,0 +1,16 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
fun interface GenericToAny<T> {
fun invoke(x: T): Any
}
fun interface GenericCharToAny : GenericToAny<Char> {
override fun invoke(x: Char): Any
}
fun withK(fn: GenericCharToAny) = fn.invoke('K').toString()
fun box(): String =
withK { "O" + it }
@@ -0,0 +1,17 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
fun interface GenericToAny<T> {
fun invoke(x: T): Any
}
fun interface GenericIntToAny : GenericToAny<Int>
fun with4(fn: GenericIntToAny) = fn.invoke(4).toString()
fun box(): String =
with4 {
if (it != 4) throw Exception()
"OK"
}
@@ -0,0 +1,14 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
fun interface GenericToAny<T> {
fun invoke(x: T): Any
}
fun interface GenericStringToAny : GenericToAny<String>
fun withK(fn: GenericStringToAny) = fn.invoke("K").toString()
fun box(): String =
withK { "O" + it }
@@ -0,0 +1,22 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
fun interface IFoo<T> {
fun foo(): T
}
fun interface IFooUnit : IFoo<Unit> {
override fun foo()
}
fun <T> fooT(iFoo: IFoo<T>) = iFoo.foo()
fun fooUnit(iFooUnit: IFooUnit) { iFooUnit.foo() }
var ok = "Failed"
fun box(): String {
fooT { ok = "O" }
fooUnit { ok += "K" }
return ok
}
@@ -0,0 +1,40 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// WITH_RUNTIME
fun interface IFooT<T> {
fun foo(x: T): T
}
fun interface IFooIntArray {
fun foo(x: IntArray): IntArray
}
fun interface IFooMix0 : IFooT<IntArray>, IFooIntArray
fun interface IFooMix1 : IFooT<IntArray>, IFooIntArray {
override fun foo(x: IntArray): IntArray
}
fun box(): String {
var t0 = "Failed 0"
val f0 = IFooMix0 {
t0 = "O" + it[0].toChar()
it
}
f0.foo(intArrayOf('K'.toInt()))
if (t0 != "OK")
return "Failed: t0=$t0"
var t1 = "Failed 1"
val f1 = IFooMix1 {
t1 = it[0].toChar() + "K"
it
}
f1.foo(intArrayOf('O'.toInt()))
if (t1 != "OK")
return "Failed: t1=$t1"
return "OK"
}
@@ -0,0 +1,29 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
fun interface IFooT<T> {
fun foo(x: T): T
}
fun interface IFooStr {
fun foo(x: String): String
}
fun interface IFooMix0 : IFooT<String>, IFooStr
fun interface IFooMix1 : IFooT<String>, IFooStr {
override fun foo(x: String): String
}
fun box(): String {
val f0 = IFooMix0 { "O" + it }
if (f0.foo("K") != "OK")
return "Failed: f0.foo(\"K\")=${f0.foo("K")}"
val f1 = IFooMix1 { it + "K" }
if (f1.foo("O") != "OK")
return "Failed: f1.foo(\"O\")=${f1.foo("O")}"
return "OK"
}
@@ -0,0 +1,32 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
// WITH_RUNTIME
fun interface IFooT<T> {
fun foo(x: Array<T>): T
}
fun interface IFooStr {
fun foo(x: Array<String>): String
}
fun interface IFooMix0 : IFooT<String>, IFooStr
fun interface IFooMix1 : IFooT<String>, IFooStr {
override fun foo(x: Array<String>): String
}
fun box(): String {
val f0 = IFooMix0 { "O" + it[0] }
val t0 = f0.foo(arrayOf("K"))
if (t0 != "OK")
return "Failed: t0=$t0"
val f1 = IFooMix1 { it[0] + "K" }
val t1 = f1.foo(arrayOf("O"))
if (t1 != "OK")
return "Failed: t1=$t1"
return "OK"
}
@@ -0,0 +1,32 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM
// IGNORE_LIGHT_ANALYSIS
// JVM_TARGET: 1.8
// SAM_CONVERSIONS: INDY
fun interface IFooT<T> {
fun foo(x: T): T
}
fun interface IFooInt {
fun foo(x: Int): Int
}
fun interface IFooMixed0 : IFooInt, IFooT<Int>
fun interface IFooMixed1 : IFooInt, IFooT<Int> {
override fun foo(x: Int): Int
}
fun box(): String {
val f0 = IFooMixed0 { it * 2 }
if (f0.foo(21) != 42)
return "Failed: f0.foo(21)=${f0.foo(21)}"
val f1 = IFooMixed1 { it * 2 }
if (f1.foo(21) != 42)
return "Failed: f1.foo(21)=${f1.foo(21)}"
return "OK"
}
@@ -1,6 +1,6 @@
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// LAMBDAS: INDY
// SAM_CONVERSIONS: INDY
fun interface IFoo<T> {
fun foo(): T
@@ -1,4 +1,6 @@
// TARGET_BACKEND: JVM
// SAM_CONVERSIONS: CLASS
// ^ SAM-convertion classes created with LambdaMetafactory have 'enclosingMethod' and 'enclosingClass'
// WITH_REFLECT
package test
@@ -17,7 +19,7 @@ fun box(): String {
val javaClass = lambda.javaClass
val enclosingMethod = javaClass.getEnclosingMethod()
if (enclosingMethod?.getName() != "run") return "method: $enclosingMethod"
if (enclosingMethod?.getName() != "run") return "enclosing method: $enclosingMethod"
val enclosingClass = javaClass.getEnclosingClass()!!.getName()
if (enclosingClass != "test.A\$prop\$1") return "enclosing class: $enclosingClass"
@@ -1,4 +1,6 @@
// TARGET_BACKEND: JVM
// SAM_CONVERSIONS: CLASS
// ^ test checks reflection for synthetic classes
// MODULE: lib
// FILE: JavaClass.java
+2
View File
@@ -1,5 +1,7 @@
// TARGET_BACKEND: JVM
// SKIP_JDK6
// SAM_CONVERSIONS: CLASS
// ^ test checks reflection for synthetic classes
// MODULE: lib
// FILE: Custom.java
@@ -1,5 +1,7 @@
// TARGET_BACKEND: JVM
// SKIP_JDK6
// SAM_CONVERSIONS: CLASS
// ^ test checks reflection for synthetic classes
// MODULE: lib
// FILE: Custom.java
+2
View File
@@ -1,6 +1,8 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// SAM_CONVERSIONS: CLASS
// ^ test checks reflection for synthetic classes
// MODULE: lib
// FILE: Promise.java
import org.jetbrains.annotations.NotNull;
@@ -2,6 +2,8 @@
// WITH_REFLECT
// FULL_JDK
// TARGET_BACKEND: JVM
// SAM_CONVERSIONS: CLASS
// ^ SAM-convertion classes created with LambdaMetafactory have no generic signatures
// FILE: Provider.java
@@ -2,6 +2,8 @@
// TARGET_BACKEND: JVM
// SKIP_JDK6
// WITH_RUNTIME
// SAM_CONVERSIONS: CLASS
// ^ test checks reflection for synthetic classes
// MODULE: lib
// FILE: JavaClass.java
@@ -1,3 +1,4 @@
// SAM_CONVERSIONS: CLASS
// FILE: samAdapterForJavaInterfaceWithNullability.kt
fun testNullable(s: String) = JNullable { s }
fun testNotNull(s: String) = JNotNull { s }
@@ -1,40 +1,10 @@
@kotlin.Metadata
final class SamAdapterForJavaInterfaceWithNullabilityKt$testNoAnnotation$1 {
// source: 'samAdapterForJavaInterfaceWithNullability.kt'
enclosing method SamAdapterForJavaInterfaceWithNullabilityKt.testNoAnnotation(Ljava/lang/String;)LJNoAnnotation;
synthetic final field $s: java.lang.String
inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNoAnnotation$1
method <init>(p0: java.lang.String): void
public final method getString(): java.lang.String
}
@kotlin.Metadata
final class SamAdapterForJavaInterfaceWithNullabilityKt$testNotNull$1 {
// source: 'samAdapterForJavaInterfaceWithNullability.kt'
enclosing method SamAdapterForJavaInterfaceWithNullabilityKt.testNotNull(Ljava/lang/String;)LJNotNull;
synthetic final field $s: java.lang.String
inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNotNull$1
method <init>(p0: java.lang.String): void
public final @org.jetbrains.annotations.NotNull method getNullableString(): java.lang.String
}
@kotlin.Metadata
final class SamAdapterForJavaInterfaceWithNullabilityKt$testNullable$1 {
// source: 'samAdapterForJavaInterfaceWithNullability.kt'
enclosing method SamAdapterForJavaInterfaceWithNullabilityKt.testNullable(Ljava/lang/String;)LJNullable;
synthetic final field $s: java.lang.String
inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNullable$1
method <init>(p0: java.lang.String): void
public final @org.jetbrains.annotations.Nullable method getNullableString(): java.lang.String
}
@kotlin.Metadata
public final class SamAdapterForJavaInterfaceWithNullabilityKt {
// source: 'samAdapterForJavaInterfaceWithNullability.kt'
inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNoAnnotation$1
inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNotNull$1
inner (anonymous) class SamAdapterForJavaInterfaceWithNullabilityKt$testNullable$1
private final static method testNoAnnotation$lambda-2(p0: java.lang.String): java.lang.String
public final static @org.jetbrains.annotations.NotNull method testNoAnnotation(@org.jetbrains.annotations.NotNull p0: java.lang.String): JNoAnnotation
private final static method testNotNull$lambda-1(p0: java.lang.String): java.lang.String
public final static @org.jetbrains.annotations.NotNull method testNotNull(@org.jetbrains.annotations.NotNull p0: java.lang.String): JNotNull
private final static method testNullable$lambda-0(p0: java.lang.String): java.lang.String
public final static @org.jetbrains.annotations.NotNull method testNullable(@org.jetbrains.annotations.NotNull p0: java.lang.String): JNullable
}
@@ -1,3 +1,4 @@
// SAM_CONVERSIONS: CLASS
// WITH_SIGNATURES
// FILE: t.kt
fun main(x: DataStream<Int>) {
@@ -1,31 +1,7 @@
@kotlin.Metadata
final class<<IN:Ljava/lang/Object;KEY:Ljava/lang/Object;>Ljava/lang/Object;LKeySelector<Ljava/lang/Integer;Ljava/lang/Long;>;> TKt$main$1 {
// source: 't.kt'
static <null> method <clinit>(): void
<null> method <init>(): void
public final <null> method getKey(p0: java.lang.Integer): java.lang.Long
public synthetic bridge <null> method getKey(p0: java.lang.Object): java.lang.Object
enclosing method TKt.main(LDataStream;)V
public final static field <LTKt$main$1<TIN;TKEY;>;> INSTANCE: TKt$main$1
inner (anonymous) class TKt$main$1
}
@kotlin.Metadata
final class<<IN:Ljava/lang/Object;KEY:Ljava/lang/Object;>Ljava/lang/Object;LKeySelector<Ljava/lang/Integer;Ljava/lang/Long;>;> TKt$main$2 {
// source: 't.kt'
static <null> method <clinit>(): void
<null> method <init>(): void
public final <null> method getKey(p0: java.lang.Integer): java.lang.Long
public synthetic bridge <null> method getKey(p0: java.lang.Object): java.lang.Object
enclosing method TKt.main(LDataStream;)V
public final static field <LTKt$main$2<TIN;TKEY;>;> INSTANCE: TKt$main$2
inner (anonymous) class TKt$main$2
}
@kotlin.Metadata
public final class<null> TKt {
// source: 't.kt'
public final static <(LDataStream<Ljava/lang/Integer;>;)V> method main(@org.jetbrains.annotations.NotNull p0: DataStream): void
inner (anonymous) class TKt$main$1
inner (anonymous) class TKt$main$2
private final static <null> method main$lambda-0(p0: java.lang.Integer): java.lang.Long
private final static <null> method main$lambda-1(p0: java.lang.Integer): java.lang.Long
}
@@ -4,20 +4,10 @@ public interface<<T:Ljava/lang/Object;>Ljava/lang/Object;> Sam {
public abstract <()TT;> method get(): java.lang.Object
}
@kotlin.Metadata
final class<<T:Ljava/lang/Object;>Ljava/lang/Object;LSam<TT;>;> TKt$genericSamGet$1 {
// source: 't.kt'
public final <()TT;> method get(): java.lang.Object
<(Lkotlin/jvm/functions/Function0<+TT;>;)V> method <init>(p0: kotlin.jvm.functions.Function0): void
enclosing method TKt.genericSamGet(Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
synthetic final field <Lkotlin/jvm/functions/Function0<TT;>;> $f: kotlin.jvm.functions.Function0
inner (anonymous) class TKt$genericSamGet$1
}
@kotlin.Metadata
public final class<null> TKt {
// source: 't.kt'
public final static <<T:Ljava/lang/Object;>(LSam<TT;>;)TT;> method expectsSam(@org.jetbrains.annotations.NotNull p0: Sam): java.lang.Object
private final static <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet$lambda-0(p0: kotlin.jvm.functions.Function0): java.lang.Object
public final static <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Object
inner (anonymous) class TKt$genericSamGet$1
}
@@ -1,28 +1,8 @@
@kotlin.Metadata
final class<<T:Ljava/lang/Object;>Ljava/lang/Object;LSam<TT;>;> TKt$genericSam$1 {
// source: 't.kt'
public final <()TT;> method get(): java.lang.Object
<(Lkotlin/jvm/functions/Function0<+TT;>;)V> method <init>(p0: kotlin.jvm.functions.Function0): void
enclosing method TKt.genericSam(Lkotlin/jvm/functions/Function0;)LSam;
synthetic final field <Lkotlin/jvm/functions/Function0<TT;>;> $f: kotlin.jvm.functions.Function0
inner (anonymous) class TKt$genericSam$1
}
@kotlin.Metadata
final class<<T:Ljava/lang/Object;>Ljava/lang/Object;LSam<TT;>;> TKt$genericSamGet$1 {
// source: 't.kt'
public final <()TT;> method get(): java.lang.Object
<(Lkotlin/jvm/functions/Function0<+TT;>;)V> method <init>(p0: kotlin.jvm.functions.Function0): void
enclosing method TKt.genericSamGet(Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
synthetic final field <Lkotlin/jvm/functions/Function0<TT;>;> $f: kotlin.jvm.functions.Function0
inner (anonymous) class TKt$genericSamGet$1
}
@kotlin.Metadata
public final class<null> TKt {
// source: 't.kt'
public final static @org.jetbrains.annotations.NotNull <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)LSam<TT;>;> method genericSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): Sam
private final static <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSam$lambda-0(p0: kotlin.jvm.functions.Function0): java.lang.Object
private final static <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet$lambda-1(p0: kotlin.jvm.functions.Function0): java.lang.Object
public final static <<T:Ljava/lang/Object;>(Lkotlin/jvm/functions/Function0<+TT;>;)TT;> method genericSamGet(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Object
inner (anonymous) class TKt$genericSam$1
inner (anonymous) class TKt$genericSamGet$1
}
@@ -1,3 +1,4 @@
// WITH_SIGNATURES
// FILE: t.kt
@@ -4,21 +4,10 @@ public interface<<T:Ljava/lang/Object;>Ljava/lang/Object;> Sam {
public abstract <()TT;> method get(): java.lang.Object
}
@kotlin.Metadata
final class<<T:Ljava/lang/Object;>Ljava/lang/Object;LSam<Ljava/lang/String;>;> TKt$specializedSam$1 {
// source: 't.kt'
<(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)V> method <init>(p0: kotlin.jvm.functions.Function0): void
public synthetic bridge <null> method get(): java.lang.Object
public final @org.jetbrains.annotations.NotNull <null> method get(): java.lang.String
enclosing method TKt.specializedSam(Lkotlin/jvm/functions/Function0;)Ljava/lang/String;
synthetic final field <Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;> $f: kotlin.jvm.functions.Function0
inner (anonymous) class TKt$specializedSam$1
}
@kotlin.Metadata
public final class<null> TKt {
// source: 't.kt'
private final static <(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)Ljava/lang/String;> method specializedSam$lambda-0(p0: kotlin.jvm.functions.Function0): java.lang.String
public final static @org.jetbrains.annotations.NotNull <(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)Ljava/lang/String;> method specializedSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.String
public final static <<T:Ljava/lang/Object;>(LSam<TT;>;)TT;> method expectsSam(@org.jetbrains.annotations.NotNull p0: Sam): java.lang.Object
inner (anonymous) class TKt$specializedSam$1
}
@@ -1,17 +1,6 @@
@kotlin.Metadata
final class<<T:Ljava/lang/Object;>Ljava/lang/Object;LSam<Ljava/lang/String;>;> TKt$specializedSam$1 {
// source: 't.kt'
<(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)V> method <init>(p0: kotlin.jvm.functions.Function0): void
public synthetic bridge <null> method get(): java.lang.Object
public final <null> method get(): java.lang.String
enclosing method TKt.specializedSam(Lkotlin/jvm/functions/Function0;)Ljava/lang/String;
synthetic final field <Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;> $f: kotlin.jvm.functions.Function0
inner (anonymous) class TKt$specializedSam$1
}
@kotlin.Metadata
public final class<null> TKt {
// source: 't.kt'
private final static <(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)Ljava/lang/String;> method specializedSam$lambda-0(p0: kotlin.jvm.functions.Function0): java.lang.String
public final static <(Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;)Ljava/lang/String;> method specializedSam(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.String
inner (anonymous) class TKt$specializedSam$1
}
@@ -16,9 +16,9 @@ fun test() {
}
// @TestKt.class:
// 1 NEW TestKt\$
// 0 NEW TestKt\$
// 1 NEW kotlin/jvm/internal/Ref\$IntRef
// 2 NEW
// 1 NEW
// 0 IFNONNULL
// 0 IFNULL
// 1 ACONST_NULL
@@ -16,16 +16,16 @@ fun test() {
JFoo.foo2({}, runnable())
}
// 2 NEW
// JVM_TEMPLATES
// @TestKt.class:
// 2 NEW
// 0 IFNONNULL
// 1 IFNULL
// 1 ACONST_NULL
// JVM_IR_TEMPLATES
// @TestKt.class
// 1 NEW
// 1 IFNONNULL
// 0 IFNULL
// 2 ACONST_NULL
@@ -12,5 +12,5 @@ fun test() {
}
// Lambda inlined into run(), no wrapper class generated:
// 1 NEW
// 0 NEW
// 0 INVOKEINTERFACE