JVM IR: change generation scheme of property $delegate methods
Generate $delegate method as instance method in PropertyReferenceDelegationLowering, and remove dispatch receiver later in MakePropertyDelegateMethodsStatic. The method needs to be static to be non-overridable (see delegateMethodIsNonOverridable.kt), and public to be accessible in reflection. Otherwise we generated incorrect IR where a static function accessed an instance field of the containing class, which failed in multiple places including LocalDeclarationsLowering. #KT-48350 Fixed
This commit is contained in:
committed by
Alexander Udalov
parent
50508da156
commit
04c5bbdcf8
+23
@@ -0,0 +1,23 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
interface I {
|
||||
var z: String
|
||||
}
|
||||
|
||||
class X {
|
||||
var p: String = "Fail"
|
||||
}
|
||||
|
||||
class A {
|
||||
val x = X()
|
||||
|
||||
val y = object : I {
|
||||
override var z: String by x::p
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = A()
|
||||
a.y.z = "OK"
|
||||
return a.y.z
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
interface I {
|
||||
var z: String
|
||||
}
|
||||
|
||||
class X {
|
||||
var p: String = "Fail"
|
||||
}
|
||||
|
||||
class A {
|
||||
val x = X()
|
||||
|
||||
inner class Y : I {
|
||||
override var z: String by x::p
|
||||
}
|
||||
|
||||
val y = Y()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = A()
|
||||
a.y.z = "OK"
|
||||
return a.y.z
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
|
||||
val a = 1
|
||||
val b = 2
|
||||
|
||||
fun KProperty0<*>.test(): String =
|
||||
(apply { isAccessible = true }.getDelegate() as KProperty<*>).name
|
||||
|
||||
open class C {
|
||||
open val x by run { ::a }
|
||||
open val y by ::a
|
||||
|
||||
val xc = ::x.test()
|
||||
val yc = ::y.test()
|
||||
}
|
||||
|
||||
class D : C() {
|
||||
override val x by run { ::b }
|
||||
override val y by ::b
|
||||
|
||||
val xd = ::x.test()
|
||||
val yd = ::y.test()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val result = D().run { "$xc $yc $xd $yd" }
|
||||
if (result != "a a b b") return "Fail: $result"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+12
@@ -11,6 +11,8 @@ class C(var x: Int) {
|
||||
|
||||
class D(val c: C) {
|
||||
var y by c::x
|
||||
var C.w by C::x
|
||||
var Int.q by Int::x
|
||||
}
|
||||
|
||||
var x = 1
|
||||
@@ -40,6 +42,9 @@ fun <T> KMutableProperty1<T, Int>.test(receiver: T) =
|
||||
fun <T> KMutableProperty1<T, Int>.test(receiver: T, receiver2: T) =
|
||||
test({ getDelegate(receiver) as KMutableProperty1<T, Int> }, { get(receiver2) }, { set(receiver2, it) })
|
||||
|
||||
fun <R1, R2> KMutableProperty2<R1, R2, Int>.test(receiver1: R1, receiver2: R2) =
|
||||
test({ getDelegate(receiver1, receiver2) as KMutableProperty1<R2, Int> }, { get(receiver2) }, { set(receiver2, it) })
|
||||
|
||||
fun box(): String {
|
||||
C::y.test(C(100), C(1))
|
||||
C::z.test(C(1))
|
||||
@@ -47,5 +52,12 @@ fun box(): String {
|
||||
::y.test()
|
||||
::z.test()
|
||||
Int::y.test({ getExtensionDelegate() as KMutableProperty1<Int, Int> }, { get(100) }, { set(100, it) })
|
||||
|
||||
val w = D::class.members.single { it.name == "w" } as KMutableProperty2<D, C, Int>
|
||||
w.test(D(C(100)), C(1))
|
||||
|
||||
val q = D::class.members.single { it.name == "q" } as KMutableProperty2<D, Int, Int>
|
||||
q.test({ getExtensionDelegate(D(C(100))) as KMutableProperty1<Int, Int> }, { get(100) }, { set(100, it) })
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
val a = 1
|
||||
val b = 2
|
||||
|
||||
open class C {
|
||||
open val x by run { ::a }
|
||||
open val y by ::a
|
||||
}
|
||||
|
||||
class D : C() {
|
||||
override val x by run { ::b }
|
||||
override val y by ::b
|
||||
}
|
||||
Vendored
+65
@@ -0,0 +1,65 @@
|
||||
@kotlin.Metadata
|
||||
synthetic final class C$x$2$1 {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
public final static field INSTANCE: kotlin.reflect.KProperty0
|
||||
static method <clinit>(): void
|
||||
method <init>(): void
|
||||
public @org.jetbrains.annotations.Nullable method get(): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
synthetic final class C$y$2 {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
public final static field INSTANCE: kotlin.reflect.KProperty0
|
||||
static method <clinit>(): void
|
||||
method <init>(): void
|
||||
public @org.jetbrains.annotations.Nullable method get(): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public class C {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
private final @org.jetbrains.annotations.NotNull field x$delegate: kotlin.reflect.KProperty0
|
||||
private final @org.jetbrains.annotations.NotNull field y$delegate: kotlin.reflect.KProperty0
|
||||
public method <init>(): void
|
||||
public method getX(): int
|
||||
public method getY(): int
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
synthetic final class D$x$2$1 {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
public final static field INSTANCE: kotlin.reflect.KProperty0
|
||||
static method <clinit>(): void
|
||||
method <init>(): void
|
||||
public @org.jetbrains.annotations.Nullable method get(): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
synthetic final class D$y$2 {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
public final static field INSTANCE: kotlin.reflect.KProperty0
|
||||
static method <clinit>(): void
|
||||
method <init>(): void
|
||||
public @org.jetbrains.annotations.Nullable method get(): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class D {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
private final @org.jetbrains.annotations.NotNull field x$delegate: kotlin.reflect.KProperty0
|
||||
private final @org.jetbrains.annotations.NotNull field y$delegate: kotlin.reflect.KProperty0
|
||||
public method <init>(): void
|
||||
public method getX(): int
|
||||
public method getY(): int
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class DelegateMethodIsNonOverridableKt {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
private final static field a: int
|
||||
private final static field b: int
|
||||
static method <clinit>(): void
|
||||
public final static method getA(): int
|
||||
public final static method getB(): int
|
||||
}
|
||||
Vendored
+53
@@ -0,0 +1,53 @@
|
||||
@kotlin.Metadata
|
||||
synthetic final class C$x$2$1 {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
enclosing method C.<init>()V
|
||||
public final static field INSTANCE: C$x$2$1
|
||||
inner (anonymous) class C$x$2$1
|
||||
static method <clinit>(): void
|
||||
method <init>(): void
|
||||
public @org.jetbrains.annotations.Nullable method get(): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public class C {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
private final @org.jetbrains.annotations.NotNull field x$delegate: kotlin.reflect.KProperty0
|
||||
inner (anonymous) class C$x$2$1
|
||||
public method <init>(): void
|
||||
public method getX(): int
|
||||
public static method getY$delegate(p0: C): java.lang.Object
|
||||
public method getY(): int
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
synthetic final class D$x$2$1 {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
enclosing method D.<init>()V
|
||||
public final static field INSTANCE: D$x$2$1
|
||||
inner (anonymous) class D$x$2$1
|
||||
static method <clinit>(): void
|
||||
method <init>(): void
|
||||
public @org.jetbrains.annotations.Nullable method get(): java.lang.Object
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class D {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
private final @org.jetbrains.annotations.NotNull field x$delegate: kotlin.reflect.KProperty0
|
||||
inner (anonymous) class D$x$2$1
|
||||
public method <init>(): void
|
||||
public method getX(): int
|
||||
public static method getY$delegate(p0: D): java.lang.Object
|
||||
public method getY(): int
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class DelegateMethodIsNonOverridableKt {
|
||||
// source: 'delegateMethodIsNonOverridable.kt'
|
||||
private final static field a: int
|
||||
private final static field b: int
|
||||
static method <clinit>(): void
|
||||
public final static method getA(): int
|
||||
public final static method getB(): int
|
||||
}
|
||||
+2
-2
@@ -35,11 +35,11 @@ fun local() {
|
||||
// 0 private final( static)? Lkotlin/reflect/KMutableProperty[0-2]; [xyz]m?\$delegate
|
||||
// 2 private final( static)? LC; [xyz]m?\$receiver
|
||||
// 0 LOCALVARIABLE [xyz]m? Lkotlin/reflect/KMutableProperty[0-2];
|
||||
// 12 static get[XYZ]m?\$delegate
|
||||
// 12 public( static)? get[XYZ]m?\$delegate
|
||||
|
||||
// JVM_TEMPLATES
|
||||
// Not optimized, references created as classes and stored in fields:
|
||||
// 16 extends kotlin/jvm/internal/MutablePropertyReference[0-2]Impl
|
||||
// 12 private final( static)? Lkotlin/reflect/KMutableProperty[0-2]; [xyz]m?\$delegate
|
||||
// 4 LOCALVARIABLE [xyz]m? Lkotlin/reflect/KMutableProperty[0-2];
|
||||
// 0 static get[XYZ]m?\$delegate
|
||||
// 0 get[XYZ]m?\$delegate
|
||||
|
||||
Reference in New Issue
Block a user